/*global phantom:false, require:false, console:false, window:false, QUnit:false */

(function() {
    'use strict';

    var url, page, timeout, args = require('system').args;

    // arg[0]: scriptName, args[1...]: arguments
    if (args.length < 2) {
	console
		.error('Usage:\n  phantomjs [phantom arguments] runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]');
	exit(1);
    }

    url = args[1];

    if (args[2] !== undefined) {
	timeout = parseInt(args[2], 10);
    }

    page = require('webpage').create();

    // Route `console.log()` calls from within the Page context to the main
    // Phantom context (i.e. current `this`)
    page.onConsoleMessage = function(msg) {
	console.log(msg);
    };

    page.onInitialized = function() {
	page.evaluate(addLogging);
    };
    // TrinhNX 0126
    page.onResourceError = function( message ) {
	console.log(message.errorString);
    };

    page.onCallback = function(message) {

	if (message) {
	    if (message.name === 'QUnit.done') {
		exit(0);
	    }
	} else {
	    exit(1);
	}
    };
    phantom.onError = function(msg, trace) {
	    var msgStack = ['PHANTOM ERROR: ' + msg];
	    if (trace && trace.length) {
	        msgStack.push('TRACE:');
	        trace.forEach(function(t) {
	            msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line );
	        });
	    }
	    console.error(msgStack.join('\n'));
	    phantom.exit(1);
	};
    page.open(url, function(status) {
	if (status !== 'success') {
	    console.log(url);
	    console.error('Unable to access network: '+ status);
			    exit(1);
	} else {
	    // Cannot do this verification with the
	    // 'DOMContentLoaded' handler because it
	    // will be too late to attach it if a page does not
	    // have any script tags.
	    var qunitMissing = page.evaluate(function() {
		return (typeof QUnit === 'undefined' || !QUnit);
	    });
	    if (qunitMissing) {
		console.error('The `QUnit` object is not present on this page.');
		exit(1);
	    }

	    // Set a default timeout value if the user does not
	    // provide one
	    if (typeof timeout === 'undefined') {
		timeout = 60; // Time out is 1 min
	    }
	    
	    // Set a timeout on the test running, otherwise
	    // tests with async problems will hang forever
	    setTimeout(function() {
		console.error('The specified timeout of '
			+ timeout
			+ ' seconds has expired. Aborting...');
		exit(1);
	    }, timeout * 1000);
	    
	    // Do nothing... the callback mechanism will handle
	    // everything!
	}
    });

    function addLogging() {
	window.document.addEventListener('DOMContentLoaded', function() {

	    QUnit.done(function(result) {
		// console.log(result.xml);
		// console.log('\n' + 'Took ' + result.runtime + 'ms to run ' +
		// result.total + ' tests. ' + result.passed + ' passed, ' +
		// result.failed + ' failed.');

		if (typeof window.callPhantom === 'function') {
		    window.callPhantom({
			'name' : 'QUnit.done',
			'data' : result
		    });
		}
	    });
	}, false);
    }

    function exit(code) {
	if (page) {
	    page.close();
	}
	setTimeout(function() {
	    phantom.exit(code);
	}, 0);
	phantom.onError = function(){};
    }
})();
